package edu.friday.service.impl;

import edu.friday.common.constant.UserConstants;
import edu.friday.common.result.TreeSelect;
import edu.friday.model.SysMenu;
import edu.friday.model.vo.MetaVo;
import edu.friday.model.vo.RouterVO;
import edu.friday.model.vo.SysMenuVO;
import edu.friday.model.vo.SysUserVO;
import edu.friday.repository.SysMenuRepository;
import edu.friday.service.SysMenuService;
import edu.friday.utils.BeanUtils;
import edu.friday.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class SysMenuServiceImpl implements SysMenuService {
    @Autowired
    SysMenuRepository menuRepository;
    @Override
    public List<SysMenu> selectMenuAll() {
        return menuRepository.findAll();
    }

    @Override
    public List<Long> selectMenuListByRoleId(Long roleId) {
        return menuRepository.selectRoleIdsByRoleMenu(roleId);
    }

    @Override
    public List<Long> selectMenuRoleId(Long roleId) {
        return menuRepository.selectRoleIdsByRoleMenuAll(roleId);
    }

    @Override
    public Set<String> selectMenuPermsByUserId(Long userId) {
        List<String> perms=menuRepository.selectMenuPermsByUserId(userId);
        Set<String> permsSet=new HashSet<>();
        for (String perm : perms) {
            if (StringUtils.isNotNull(perm)) {
                permsSet.addAll(Arrays.asList(perm.trim().split(",")));
            }
        }
        return permsSet;
    }

    @Override
    public List<SysMenu> selectMenuList(SysMenuVO menuVO, Long userId) {
        List<SysMenu> menuList=null;
        SysMenu sysMenu=new SysMenu();
        BeanUtils.copyPropertiesIgnoreEmpty(menuVO,sysMenu);
        Sort sort=Sort.by("parentId","orderNum");
        ExampleMatcher exampleMatcher=ExampleMatcher.matching()
                .withMatcher("menuName",ExampleMatcher.GenericPropertyMatchers.contains());
        Example example=Example.of(sysMenu,exampleMatcher);
        if (SysUserVO.isAdmin(userId)) {
            menuList=menuRepository.findAll(example,sort);
        }else {
            menuList=menuRepository.selectMenuListByUserId(sysMenu,userId);
        }
        return menuList;
    }

    @Override
    public SysMenu selectMenuById(Long menuId) {
        Optional<SysMenu> op=menuRepository.findById(menuId);
        return op.isPresent()?op.get():null;
    }

    @Override
    public List<TreeSelect> buildMenuTreeSelect(List<SysMenuVO> menuVOS) {
        List<SysMenuVO> menuTree=buildMenuTree(menuVOS);
        List<TreeSelect> rs=menuTree.stream().map(TreeSelect::new).collect(Collectors.toList());
        return rs;
    }

    @Override
    public List<SysMenuVO> buildMenuTree(List<SysMenuVO> menuVOS) {
        List<SysMenuVO> returnList=new ArrayList<SysMenuVO>();
        for (Iterator<SysMenuVO> iterator=menuVOS.iterator();iterator.hasNext();){
            SysMenuVO t=iterator.next();
            if (t.getParentId()==0){
                recursionFn(menuVOS,t);
                returnList.add(t);
            }
        }
        if (returnList.isEmpty()){
            returnList=menuVOS;
        }
        return returnList;
    }

    private void recursionFn(List<SysMenuVO> list, SysMenuVO t) {
        List<SysMenuVO> childList=getChildList(list,t);
        t.setChildren(childList);
        for (SysMenuVO sysMenuVO : childList) {
            if (hassChild(list,sysMenuVO)){
                Iterator<SysMenuVO> it=childList.iterator();
                while (it.hasNext()){
                    SysMenuVO n=it.next();
                    recursionFn(list,n);
                }
            }
        }
    }

    private boolean hassChild(List<SysMenuVO> list, SysMenuVO sysMenuVO) {
        return getChildList(list,sysMenuVO).size()>0?true:false;
    }

    private List<SysMenuVO> getChildList(List<SysMenuVO> list, SysMenuVO t) {
        List<SysMenuVO> tlist=new ArrayList<SysMenuVO>();
        Iterator<SysMenuVO> it=list.iterator();
        while (it.hasNext()) {
            SysMenuVO n=it.next();
            if (n.getParentId().longValue()==t.getMenuId().longValue()) {
                tlist.add(n);
            }
        }
        return list;
    }

    @Override
    public List<SysMenu> selectMenuList(Long userId) {
        return null;
    }

    @Override
    public String checkMenuNameUnique(SysMenu menu) {
        Long menuId=StringUtils.isNull(menu.getMenuId())?-1L:menu.getMenuId();
        SysMenu sysMenu=new SysMenu();
        sysMenu.setParentId(menuId);
        sysMenu.setMenuName(menu.getMenuName());
        Page<SysMenu> list=menuRepository.findAll(Example.of(sysMenu), PageRequest.of(0,1));
        SysMenu info=null;
        if (list.getTotalElements()>0) {
            info=list.toList().get(0);
        }
        if (StringUtils.isNotNull(info)&& info.getMenuId().longValue()!=menuId.longValue()) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    @Override
    public int insertMenu(SysMenu menu) {
        menuRepository.save(menu);
        return (menu!=null && null!=menu.getMenuId())?1:0;
    }

    @Override
    public int updateMenu(SysMenu menu) {
        SysMenu sysMenu=new SysMenu();
        Optional<SysMenu> op=menuRepository.findById(menu.getMenuId());
        if (!op.isPresent()) {
            return 0;
        }
        sysMenu=op.get();
        BeanUtils.copyPropertiesIgnoreNull(menu,sysMenu);
        menuRepository.save(sysMenu);
        return 1;
    }

    @Override
    public int deleteMenuById(Long menuId) {
        menuRepository.deleteById(menuId);
        return 1;
    }

    @Override
    public boolean checkMenuExistRole(Long menuId) {
        long result=menuRepository.checkMenuExistRole(menuId);
        return result>0?true:false;
    }

    @Override
    public boolean hasChildByMenuId(Long menuId) {
        SysMenu sysMenu=new SysMenu();
        sysMenu.setParentId(menuId);
        long result=menuRepository.count(Example.of(sysMenu));
        return result>0?true:false;
    }

    @Override
    public List<SysMenuVO> selectMenuTreeByUserId(Long userId) {
        List<SysMenu> menus=null;
        if (SysUserVO.isAdmin(userId)) {
            menus=menuRepository.selectMenuTreeAll();
        }else {
            menus=menuRepository.selectMenuTreeByUserId(userId);
        }
        List<SysMenuVO> menuVOS=BeanUtils.copyProperties(menus,SysMenuVO.class);
        return getChildPerms(menuVOS,0);
    }

    private List<SysMenuVO> getChildPerms(List<SysMenuVO> menuVOS, int i) {
        List<SysMenuVO> returnList=new ArrayList<SysMenuVO>();
        for (Iterator<SysMenuVO> iterator=menuVOS.iterator();iterator.hasNext();){
            SysMenuVO t= iterator.next();
            if (t.getParentId()==i) {
                recursionFn(menuVOS,t);
                returnList.add(t);
            }
        }
        return returnList;
    }

    @Override
    public List<RouterVO> buildMenus(List<SysMenuVO> menus) {
        List<RouterVO> routers=new LinkedList<RouterVO>();
        for (SysMenuVO menu : menus) {
            RouterVO router=new RouterVO();
            router.setName(StringUtils.capitalize(menu.getPath()));
            router.setPath(getRouterPath(menu));
            router.setComponent(StringUtils.isEmpty(menu.getComponent())?"Layout":menu.getComponent());
            router.setMeta(new MetaVo(menu.getMenuName(),menu.getIcon()));
            List<SysMenuVO> cMenus=menu.getChildren();
            if (!cMenus.isEmpty()&&cMenus.size()>0&&"M".equals(menu.getMenuType())) {
                router.setAlwaysShow(true);
                router.setRedirect("noRedirect");
                router.setChildren(buildMenus(cMenus));
            }
            routers.add(router);
        }
        return routers;
    }

    private String getRouterPath(SysMenuVO menu) {
        String routerPath=menu.getPath();
        if (0==menu.getParentId()&&"1".equals(menu.getIsFrame())) {
            routerPath="/"+menu.getPath();
        }
        return routerPath;
    }
}
